package java_thinking.unit_15._15_10;

import java_thinking.unit_15.Holder;

/**
 * @Description :
 * @author: cww
 * @DateTime: 2019-04-06 23:02
 */

public class _3_2_Wildcards {
    /**
     * 无论何时，只要使用了原生类型，都会放弃编译器检查
     */
    static void rawArgs(Holder holder, Object arg) {
        // unchecked warning
         holder.set(arg);
        // same warning
//         holder.set(new _3_2_Wildcards());

        // compile error, don't have any T
        // T t = holder.get();

        // No warning, but type information has been lost

        Object obj = holder.get();
    }


    // 和rawArgs相似，但是其中的warning会变成编译错误

    /**
     * holder.set(arg);之所以报错，因为原生Holder将持有任何类型的组合，而Holder<?>将持有某种具体类型的同构集合，
     * 因此不能只是向其中传递Object
     *
     * Holder与Holder<?>是大致相同的事物。但现实说明它们是不同的，
     * 因为原生的Holder将持有任何类型的组合，二Holder<?>将持有具有某种具体类型的同构集合，因此不能只是向其中传递object。
     * @param holder
     * @param arg
     */
    static void unboundedArg(Holder<?> holder, Object arg) {
        // Compile Error set(capture of ?) but accept Object，为什么这里会编译报错
         // holder.set(arg);
        // same error
         // holder.set(new _3_2_Wildcards());

        // compile error, don't have any T
        // T t = holder.get();

        // No warning, but type information has been lost
        Object obj = holder.get();
    }

    static <T> T exact1(Holder<T> holder) {
        T t = holder.get();
        return t;
    }

    static <T> T exact2(Holder<T> holder, T arg) {
        holder.set(arg);
        T t = holder.get();
        return t;
    }

    /**
     * 在Holder类型上的限制被放松为持有任何扩展至T对象的Holder，
     * 这还是意味着如果T是Fruit，那么holder可以是Holder<Apple>
     * holder.set(arg) 报错是为了防止将Orange放置到Holder<Apple>中，对set()的调用
     * (或者对任何接受这个类型参数为参数的方法的调用)都是不允许的
     *
     * 你仍然知道任何来自Holder<? extends Fruit>的对象至少是Fruit，
     * 因此get()(或者任何将产生具有这个类型参数的返回值的方法)都是允许的
     */
    static <T> T wildSubtype(Holder<? extends T> holder, T arg) {
        // Error
        // set (capture<? extends T>) in Holder cannot be applied to (T)
        // holder.set(arg);
        T t = holder.get();
        return t;
    }

    /**
     * holder可以是持有任何T的基类型的容器，所以，set可以接受T，
     * 因为可以工作于基类的对象都可以多态地作于导出类(这里指的是T)。
     * 但是，尝试着调用get()是没有用的，因为由holder持有的类型是任何超类型，唯一安全的是Object
     */
    static <T> void wildSupertype(Holder<? super T> holder, T arg) {
        holder.set(arg);
        // Error
        // Required: T Found: capture<? super T>
        // T t = holder.get();

        // No warning, but type information has been lost
        Object obj = holder.get();
    }

    public static void main(String[] args) {
        Holder raw = new Holder<Long>();
        // Or
        raw = new Holder();
        Holder<Long> qualified = new Holder<>();
        Holder<?> unbounded = new Holder<Long>();
        Holder<? extends Long> bounded = new Holder<Long>();
        Long lng = 1L;

        rawArgs(raw, lng);
        rawArgs(qualified, lng);
        rawArgs(unbounded, lng);
        rawArgs(bounded, lng);

        unboundedArg(raw, lng);
        unboundedArg(qualified, lng);
        unboundedArg(unbounded, lng);
        unboundedArg(bounded, lng);

        // unchecked warning
        Object r1 = exact1(raw);
        Long r2 = exact1(qualified);
        Object r3 = exact1(unbounded);
        Long r4 = exact1(bounded);

        // unchecked warning
        Long r5 = exact2(raw, lng);
        Long r6 = exact2(qualified, lng);
        // Error 参数错误
        // Long r7 = exact2(unbounded, lng);
        // Error 参数错误
        // Long r8 = exact2(bounded, lng);

        // unchecked warning
        Long r9 = wildSubtype(raw, lng);
        Long r10 = wildSubtype(qualified, lng);
        Object r11 = wildSubtype(unbounded, lng);
        Long r12 = wildSubtype(bounded, lng);

        // unchecked warning
        wildSupertype(raw, lng);
        wildSupertype(qualified,lng);
        // Error 参数错误
        // wildSupertype(unbounded,lng);
        // wildSupertype(bounded,lng);
    }
}
